import * as _ from "lodash-es"
import { BehaviorSubject, Observable, map, mergeMap, tap } from "rxjs"
import { WASSheetCaller } from "../WASSheetCaller"

/**
 * 以行的方式读取数据
 * 
 * io并发数2
 * 
 * @param sheetCaller wps操作类
 * @param sheetName 表名
 * @param startRow 开始行
 * @param endRow 结束行
 * @param startCol 开始列
 * @param endCol 结束列
 * @returns 
 */
export function readRowObs(
    sheetCaller: WASSheetCaller,
    sheetName: string,
    startRow: number,
    endRow: number,
    startCol: number,
    endCol: number, 
): Observable<ICellRaw>
{
    let runSubj = new BehaviorSubject<{
        startRow: number,
        endRow: number,
        startCol: number,
        endCol: number,
    }>({startRow,endRow,startCol,endCol})
    let runObs = runSubj.pipe(
        tap((p) =>
        {
            let np = _.cloneDeep(p)
            np.startRow += 1
            if(np.startRow <= np.endRow)
            {
                setTimeout(() => {runSubj.next(np)})
            }else{
                setTimeout(() => {runSubj.complete()})
            }
        }),
        map(p => ({addr:`${rowNumToExcelChar(p.startCol)}${p.startRow}:${rowNumToExcelChar(p.endCol)}${p.startRow}`, p})),
        mergeMap(({addr,p}) =>
            sheetCaller.readSheetDataObs(sheetName, addr).pipe(
                map((value,index) => ({
                    value,
                    row: p.startRow,
                    col: index + p.startCol,
                    address: `${rowNumToExcelChar(index + p.startCol)}${p.startRow}`
                } satisfies ICellRaw)),
                map(cellRaw => ({cellRaw, p}))
            )
        ,2),
        map(v => v.cellRaw)
    )
    return runObs
}

/**
 * 往单元格写入数据
 * @param sheetCaller 
 * @param sheetName 
 * @param cellRaw 
 * @param value 
 * @returns 
 */
export function writeCellObs<T extends ICellRaw>(
    sheetCaller: WASSheetCaller,
    sheetName: string,
    cellRaw: T,
    value: string
): Observable<T>
{
    return sheetCaller.writeSheetDataObs(sheetName, `${cellRaw.address}:${cellRaw.address}`, [value]).pipe(
        map(() => ({...cellRaw, value} satisfies T))
    )
}

export interface ICellRaw
{
    row: number
    col: number
    address: string
    value: string
}



/**
 * 把列数转换成表格的表示方式
 *
 * 如 1 -> A, 5 -> E, 27 -> AA
 * @param num
 * @returns
 */
export function rowNumToExcelChar(num: number)
{
    let excelCharString = []
    let charStartIndex = 97
    let charIndex
    num -= 1
    for(;;)
    {
        if(num < 0 )
        {
            break
        }
        charIndex = num % 26
        excelCharString.push(String.fromCharCode(charStartIndex + charIndex))
        num = Math.floor(num / 26) - 1
    }
    return excelCharString.reverse().join("").toUpperCase()
}